package com.zzyl.security;

import cn.hutool.core.text.AntPathMatcher;
import cn.hutool.json.JSONUtil;
import com.zzyl.constant.SecurityConstant;
import com.zzyl.constant.UserCacheConstant;
import com.zzyl.properties.JwtTokenManagerProperties;
import com.zzyl.utils.JwtUtil;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.UserVo;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * @author sjqn
 * @date 2023/11/4
 */
@Component
public class JwtTokenAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private JwtTokenManagerProperties jwtTokenManagerProperties;

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {



        //获取token
        HttpServletRequest request = requestAuthorizationContext.getRequest();
        String uuidToken = request.getHeader(SecurityConstant.USER_TOKEN);
        if(ObjectUtil.isEmpty(uuidToken)){
            return new AuthorizationDecision(false);
        }
        //从redis获取jwtToken
        String jwtTokenKey = UserCacheConstant.JWT_TOKEN + uuidToken;
        String jwtToken = redisTemplate.opsForValue().get(jwtTokenKey);
        if(ObjectUtil.isEmpty(jwtToken)){
            return new AuthorizationDecision(false);
        }
        //解析数据
        Claims claims = JwtUtil.parseJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey(), jwtToken);

        //获取用户数据
        UserVo userVo = JSONUtil.toBean(String.valueOf(claims.get("currentUser")), UserVo.class);

        //从redis中获取uuid
        String userToken = redisTemplate.opsForValue().get(UserCacheConstant.USER_TOKEN+userVo.getUsername());

        if(!uuidToken.equals(userToken)){
            return new AuthorizationDecision(false);
        }

        //判断token的过期时间是否小于10分钟，如果小于，重置过期时间
        Long expire = redisTemplate.opsForValue().getOperations().getExpire(jwtTokenKey);
        if(expire <= 600){

            //续期，第一，jwtToken需要重新生成，第二：userToken只需要重新设置过期时间
            Map<String,Object> clamis = new HashMap<>();
            clamis.put("currentUser", String.valueOf(claims.get("currentUser")));

            String newJwtToken = JwtUtil.createJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey()
                    , jwtTokenManagerProperties.getTtl(), clamis);

            //过期时间计算
            long ttl = Long.valueOf(jwtTokenManagerProperties.getTtl() / 1000);

            redisTemplate.opsForValue().set(jwtTokenKey,newJwtToken,ttl, TimeUnit.SECONDS);

            redisTemplate.expire(UserCacheConstant.USER_TOKEN+userVo.getUsername(),ttl,TimeUnit.SECONDS);

        }

        //当前请求路径： GET/nursing_project/**
        String method = request.getMethod();
        String requestURI = request.getRequestURI();
        String targetUrl = method + requestURI;

        //验证用户是否拥有该资源
        /*for (String resourceRequestPath : userVo.getResourceRequestPaths()) {
            boolean isMatch = antPathMatcher.match(resourceRequestPath, targetUrl);
            if(isMatch){
                return new AuthorizationDecision(true);
            }
        }*/
        return new AuthorizationDecision(false);
    }
}
